#include "icon.h"
#include "desktop.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <dirent.h>
#include <sys/types.h>
#include <cJSON.h>

static void icon_launch(icon_t *icon)
{
    char *name, *p, *arg = NULL;
    name = icon->exec;
    p = name;
    // exec path: program name,args list
    while (*p)
    {
        if (*p == ' ')
        {
            *p = '\0';
            if (*(p + 1))
                arg = p + 1;
        }
        p++;
    }
    desktop_launch(name, arg);
}

static bool icon_button_press_event(gui_spirit_t *button, void *arg)
{
    icon_t *icon = (icon_t *)arg;
    timeval_t tv;
    if (icon->click_ms) // double click
    {
        gettimeofday(&tv, NULL);
        int tm = tv.tv_sec * 1000 + tv.tv_usec / 1000;
        if ((tm - icon->click_ms) < ICON_CLICK_DISTANCE_MS) // click distance
            icon_launch(icon);
        icon->click_ms = 0;
    }
    else
    {
        // first click time record
        gettimeofday(&tv, NULL);
        icon->click_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
    }
    return false;
}

static bool icon_button_enter_event(gui_spirit_t *button, void *arg)
{
    icon_t *icon = (icon_t *)arg;
    icon->label->style.background_color = GUI_WHITE;
    gui_spirit_show(icon->label);
    return true;
}

static int icon_button_leave_event(gui_spirit_t *button, void *arg)
{
    icon_t *icon = (icon_t *)arg;
    icon->label->style.background_color = GUI_BLACK;
    gui_spirit_show(icon->label);
    return true;
}


static int icon_create_spirit(icon_t *icon, char *name, char *icon_file)
{
    icon->button = gui_button_create();
    if (!icon->button)
    {
        return -1;
    }
    gui_spirit_set_size(icon->button, ICON_BUTTON_SIZE, ICON_BUTTON_SIZE);
    icon->button->style.border_color = GUI_COLOR_NONE;
    icon->button->style.background_color = GUI_COLOR_NONE;
    GUI_BUTTON(icon->button)->color_idle = GUI_COLOR_NONE;
    gui_signal_connect(icon->button, "button_press", icon_button_press_event, icon);
    gui_signal_connect(icon->button, "enter_notify", icon_button_enter_event, icon);
    gui_signal_connect(icon->button, "leave_notify", icon_button_leave_event, icon);

    icon->label = gui_label_create(name);
    if (!icon->label)
    {
        dprintf("[icon] create label err\n");
        gui_spirit_destroy(icon->button);
        return -1;
    }
    icon->label->style.background_color = GUI_COLOR_NONE;

    icon->icon = gui_spirit_create(0, 0, ICON_SIZE_DEFAULT, ICON_SIZE_DEFAULT);
    if (!icon->icon)
    {
        gui_spirit_destroy(icon->label);
        gui_spirit_destroy(icon->button);
        return -1;
    }
    if (gui_spirit_set_image2(icon->icon, icon_file, -1, -1) < 0)
    {
        printf("icon: set image failed!\n");
    } 
    return 0;
}

icon_t *icon_create(char *name, char *exec, char *icon_file)
{
    //dprintf("icon create name %s exec %s icon file %s\n", name, exec, icon_file);
    icon_t *icon = malloc(sizeof(icon_t));
    if (!icon)
        return NULL;
    if (icon_create_spirit(icon, name, icon_file) < 0)
    {
        free(icon);
        return NULL;
    }
    memset(icon->exec, 0, MAX_PATH_LEN+1);
    strcpy(icon->exec, exec);
    icon->terminal = false;
    icon->type = ICON_TYPE_APP;
    icon->click_ms = 0;
    list_add_tail(&icon->list, &desktop.icon_list);
    return icon;
}

void icon_destroy(icon_t *icon)
{
    list_del_init(&icon->list);
    gui_spirit_destroy(icon->button);
    gui_spirit_destroy(icon->icon);
    gui_spirit_destroy(icon->label);
    free(icon);
    return 0;
}

void icon_add(icon_t *icon, gui_spirit_t *window)
{
    gui_container_add(GUI_CONTAINER(window), icon->button);
    gui_container_add(GUI_CONTAINER(window), icon->icon);
    gui_container_add(GUI_CONTAINER(window), icon->label);
}

void icon_remove(icon_t *icon, gui_spirit_t *window)
{
    gui_container_remove(GUI_CONTAINER(window), icon->button);
    gui_container_remove(GUI_CONTAINER(window), icon->icon);
    gui_container_remove(GUI_CONTAINER(window), icon->label);
}

int icon_locate(icon_t *icon, int x, int y)
{
    if (!icon)
        return -1;

    icon->x = x;
    icon->y = y;
    //dprintf("[icon] locate: x %d y %d label %s label len %d\n",x,y,icon->label->text);
    int width = icon->button->width;
   
    gui_spirit_set_pos(icon->button, icon->x, icon->y);
    gui_spirit_set_pos(icon->icon,
        icon->x + (width / 2) - icon->icon->width / 2,
        icon->y + 3);
    gui_spirit_set_pos(icon->label,
        icon->x + (width / 2) - gui_label_width(icon->label) / 2 - 2,
        icon->icon->y + icon->icon->height + 2);
    return 0;
}


//icon locate setting
int icon_locate_all()
{
    icon_t *icon;
    int x, y;
    x = desktop.icon_x;
    y = desktop.icon_y;

    list_traversal_all_owner_to_next(icon, &desktop.icon_list, list)
    {
        icon_locate(icon, x, y);
        // next icon
        y += ICON_BUTTON_SIZE + ICON_DISTANCE;
        // next row
        if (y >= desktop.window->height - (ICON_BUTTON_SIZE + ICON_DISTANCE))
        {
            x += ICON_BUTTON_SIZE + ICON_DISTANCE;
            y = desktop.icon_y;
        }
    }
    return 0;
}

void icon_paint(icon_t *icon)
{
    gui_spirit_show(icon->button);
    gui_spirit_show(icon->icon);
    gui_spirit_show(icon->label);
}

void icon_paint_all()
{
    icon_t *icon;
    list_traversal_all_owner_to_next(icon, &desktop.icon_list, list)
    {
        icon_paint(icon);
    }
}

static int icon_read_from_json(cJSON *root)
{
    cJSON *item = NULL;
    char *name = NULL, *exec = NULL, *iconpath = NULL, *terminal = NULL, *type = NULL;
    int ver;

    item = cJSON_GetObjectItem(root, "Version");
    ver = item->valueint;
    if (ver != 1)
    {
        dprintf("[icon] verison err\n");
        return -1;
    }
    item = cJSON_GetObjectItem(root, "Name");
    if (!item)
        return -1;
    name = item->valuestring;
    if (!name)
        return -1;
    item = cJSON_GetObjectItem(root, "Exec");
    if (!item)
        return -1;
    exec = item->valuestring;
    if (!exec)
        return -1;
    item = cJSON_GetObjectItem(root, "Icon");
    if (!item)
        return -1;
    iconpath = item->valuestring;
    item = cJSON_GetObjectItem(root, "Type");
    if (!item)
        return -1;
    type = item->valuestring;
    item = cJSON_GetObjectItem(root, "Terminal");
    if (!item)
        terminal = "false";
    else
    {
        terminal = item->valuestring;
        if (!terminal)
            terminal = "false";
    }

    icon_t *icon = icon_create(name, exec, iconpath);
    if (!icon)
    {
        dprintf("[icon] create icon failed!\n");
        return -1;
    }

    icon->terminal = (!(strcmp(terminal, "true")) ? true : false);
    if (!strcmp(type, "Application"))
        icon->type = ICON_TYPE_APP;
    else if (!strcmp(type, "Link"))
        icon->type = ICON_TYPE_LINK;
    else
        icon->type = ICON_TYPE_UNKNOWN;

    icon_add(icon, desktop.window);

    return 0;
}

static int icon_read_desktop_file(char *path)
{
    dprintf("[desktop] read desktop config %s\n", path);
    FILE *fp = fopen(path, "r");
    if (!fp)
    {
        dprintf("icon: open file %s failed!\n");
        return -1;
    }

    status_t fstu;
    stat(path, &fstu);
    int filesz = fstu.st_size;
    //dprintf("[desktop] config file size %d\n", filesz);

    char *jsonStr = malloc(filesz + 1);
    if (!jsonStr)
    {
        dprintf("[icon] malloc for json str failed!\n");
        fclose(fp);
        return -1;
    }
    if (fread(jsonStr, filesz, 1, fp) <= 0)
    {
        dprintf("[icon] read json file failed!\n");
        free(jsonStr);
        fclose(fp);
        return -1;
    }
    fclose(fp);

    // dprintf("read data json %s\n",jsonStr);
    cJSON_InitHooks(NULL);
    cJSON *root = NULL;
    root = cJSON_Parse(jsonStr);
    if (!root)
    {
        dprintf("[icon] json parse error!\n");
        free(jsonStr);
        fclose(fp);
        return -1;
    }
    else
    {

        if (icon_read_from_json(root) < 0)
        {
            dprintf("[icon] read from json failed!\n");
            free(jsonStr);
            fclose(fp);
            return -1;
        }
    }
    free(jsonStr);
    fclose(fp);
    return 0;
}


void icon_dump()
{
    icon_t *icon=NULL;
    int x=0,y=0;
    list_traversal_all_owner_to_next(icon,&desktop.icon_list,list)
    {
        dprintf("icon name %s\n",icon->label->text);
        icon->label->x=x; icon->label->y=y;
        y+=20;
        gui_spirit_show(icon->label);
    }
}

void icon_scan()
{
    DIR *dir = opendir(DESKTOP_DIR);
    if (!dir)
    {
        dprintf("[desktop] open dir %s failed!\n");
        return;
    }

    while (1)
    {
        dirent_t *de = readdir(dir);
        if (!de)
            break;
        if (!(de->d_attr & DE_DIR))
        {
            char name[MAX_PATH_LEN+1] = {0};
            strcpy(name, DESKTOP_DIR);
            strcat(name, "/");
            strcat(name, de->d_name);
            icon_read_desktop_file(name);
        }
    }
    closedir(dir);

    //icon_dump();
}

int icon_init()
{
    icon_scan();
    icon_locate_all();
    icon_paint_all();
}